package injection;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.ResourceLoader;

import javax.annotation.PostConstruct;

/**
 * 依赖来源，依赖注入和依赖查找的来源不同
 * @author jackcfan
 * @date 2021/9/23
 */
public class ResolvableDependencySourceTest {
    /**
     * 内建对象注入
     * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates}
     * Autowired 在 {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 方法执行
     * 早于 setter 注入，也早于 @PostConstruct
     * */
    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    // PostConstruct 注解用于需要在依赖注入完成后执行任何初始化的方法。 必须在类投入使用之前调用此方法
    @PostConstruct
    public void initByInjection(){
        System.out.println("-----------------init 依赖注入----------------");
        System.out.println("beanFactory != applicationContext " + (beanFactory != applicationContext));
        System.out.println("beanFactory == applicationContext.getBeanFactory() " + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
        System.out.println("resourceLoader == applicationContext " + (resourceLoader == applicationContext));
        System.out.println("ApplicationEventPublisher == applicationContext " + (applicationEventPublisher == applicationContext));

    }

    /**
     * 4个 spring 内建对象无法通过依赖查找，报 NoSuchBeanDefinitionException
     * */
    @PostConstruct
    public void initByLookup(){
        System.err.println("-----------------init 依赖查找----------------");
        getBean(BeanFactory.class);
        getBean(ResourceLoader.class);
        getBean(ApplicationContext.class);
        getBean(ApplicationEventPublisher.class);
    }

    private <T>T getBean(Class<T> beanType){
        try {
            return beanFactory.getBean(beanType);
        }catch (NoSuchBeanDefinitionException e){
            System.err.println("NoSuchBeanDefinitionException : "+beanType.getName());
        }
        return null;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ResolvableDependencySourceTest.class);

        applicationContext.refresh();

        ResolvableDependencySourceTest test = applicationContext.getBean(ResolvableDependencySourceTest.class);

        applicationContext.close();
    }
}
